iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
IT Operation

地端機房的三十天維運:開源服務封裝、GPU 節點守護與可稽核的變更管理系列 第 24 篇

Day 24|稽核問「某台工作站上個月連到哪裡了」?FortiGate AUP 雙軌日誌實踐:線上 LogsQL 檢索與離線對帳修煉

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20261008/20141816KjZ6bD2oHS.png

工作站的可接受使用政策(AUP):FortiGate 日誌的兩條線,線上查與離線看

TL;DR:可接受使用政策(AUP)在稽核時考的是「這台工作站上個月去了哪裡」的資料溯源能力。本文實作兩條分析線,一條是自管邊界 FortiGate 接 VictoriaLogs 做即時 LogsQL 分析與 Prometheus 告警。另一條是針對代管設備匯出檔、具備個資防護的純前端解析器(fortigate-log-viewer)。文內完整記錄 FortiOS 7.6.7 授權過期斷網危機、時區 UTC+8 飄移、日誌時間對帳等一線維運碰到的問題實錄。


前言:政策要有紀錄才能稽核,紀錄在邊界那台防火牆上

可接受使用政策(Acceptable Use Policy, AUP)通常是一份寫在公司文件中的漂亮規章,規範同仁哪些網站能上、哪些業務不能碰。但在外部稽核或內部調查的會議室裡,沒有稽核員會考你這幾條內容,所有人只會盯著你看:

「某台涉案或中毒的工作站,上個月到底連了哪些外部網站?你拿得出客觀證據嗎?」

這個問題的標準答案,就在邊界防火牆上。

在 [Day 22] 中,我利用 FortiGate 的 type="traffic" action="deny" 回答了「誰在敲我的外部節點」(外部資安事件)。今天改用它的 type="utm" subtype="webfilter" 來回答「內網的人從哪台工作站去了哪裡」。這不僅對應資安事件調查,更是 IT 通用控制(ITGC)中「使用者活動紀錄具備可追溯性」的核心要件。

在真實的企業維運中,日誌通常會面臨兩種情境,本文將以雙軌架構並行推進:

  1. 線上即時軌(自管設備):內網自己維運的 FortiGate,將 Syslog 接進 [Day 21] 打造的 VictoriaLogs,使用 LogsQL 查詢、依 [Day 20] 的規則產生告警,並遵循自動保存週期。
  2. 離線分析軌(代管設備):中華電信資安艦隊或委外託管的防火牆,維運團隊拿不到 Syslog 轉送設定權,只能定期下載匯出檔(.log / .csv)。因此拿了一個之前做過的在瀏覽器記憶體內解析、零連網外洩風險的離線檢視工具。

這兩條線使用同一套欄位轉換定義,這樣一來,同一份日誌在線上與離線跑出來的統計數字自然分毫不差。


一、先讓防火牆好好把日誌記下來

1. 產生日誌的三個關鍵變更

場域驗證設備為自行管理的 FortiGate 60F,韌體版本為 FortiOS 7.6.7。要讓防火牆吐出 WebFilter 日誌,需執行三項變更。變更前務必依 [Day 22] 流程先執行組態備份(POST /api/v2/monitor/system/config/backup):

變更一:確認 FortiGuard Web Filtering 授權與保命開關

日誌中的 catdesc(如 Gambling、Phishing、Information Technology)是由 FortiGuard 動態評等給予的。可透過 GUI 的 System → FortiGuard 或 REST API 檢視授權狀態:

GET /api/v2/monitor/license/status

授權過期時的「全網斷網」陷阱

本實測場域 FortiGate 防火牆的 Web Filtering 授權剛好過期。請特別注意:沒有授權時,FortiGate 不是只把類別留白而已!
每一筆日誌都會被標記為 eventtype="ftgd_err" level="error" msg="A rating error occurs"。若防護 Profile 沒有啟用 set options error-allow,防火牆預設會阻擋所有評等失敗的網站,導致整個內網瞬間斷網!有授權的場域也務必開啟此選項,防範 FortiGuard 雲端服務不可達時發生大範圍意外。

變更二:建立「全監看、只擋緊急威脅」的 Profile

至 Security Profiles → Web Filter 新增 aup-monitor,設定原則為:

  • FortiGuard 類別:全面設為 Monitor(放行並留存紀錄,產生 action="passthrough")。
  • 重大威脅類別:針對 Malicious Websites(26)、Phishing(61)、Spam URLs(86)設為 Block。
  • 錯誤放行:勾選「評等錯誤時放行」(error-allow)。

CLI 實作設定如下:

config webfilter profile
    edit "aup-monitor"
        config ftgd-wf
            set options error-allow
            config filters
                edit 1
                    set category 1
                next
                # ... 各類別預設為 monitor
                edit 35
                    set category 26
                    set action block
                next
                # 61 (Phishing), 86 (Spam URLs) 同樣配置為 block
            end
        end
    next
end

變更三:將 Profile 掛載至對外政策(Policy 1)

config firewall policy
    edit 1
        set utm-status enable
        set ssl-ssh-profile "certificate-inspection"
        set webfilter-profile "aup-monitor"
        set logtraffic utm
    next
end

隱私與安全平衡點:為什麼選擇 certificate-inspection?

certificate-inspection 僅分析 TLS Handshake 階段的 SNI(Server Name Indication)與憑證內容,不進行封包解密(No Deep SSL Inspection)。
因此 HTTPS 的日誌紀錄只會呈現完整網域名稱(URL 為 https://<hostname>/),不會留下具體網址路徑。這在隱私權保護(AUP)上是刻意的設計——我只需要證明同仁在上班時間去了哪個站點,不應也不需窺探其瀏覽的具體內容。

同時請注意,FortiOS 7.6.7 預設會阻擋憑證失效、過期、低於 TLS 1.1 以及帶有 ECH(Encrypted Client Hello)的連線,此變更會提高連線標準的嚴格程度,需詳列於你在 ISO27001 相關的系統變更單中。


2. 首筆日誌驗證與流量暴增預估

在改完 Policy 後 5 秒鐘,收集端即刻抓到首筆事件:

eventtime=1791389685837697000 tz="+0800" logid="0318012800" type="utm" subtype="webfilter"
eventtype="ftgd_err" level="error" vd="root" policyid=1 policytype="policy" sessionid=12658995
srcip=ws-01 srcport=64018 srcintf="internal" srcintfrole="lan" dstip=203.0.113.134 dstport=80
dstintf="wan1" dstintfrole="wan" proto=6 httpmethod="GET" service="HTTP" hostname="site-168.example"
profile="aup-monitor" action="passthrough" reqtype="direct" url="http://site-168.example/generate_204"
sentbyte=320 rcvdbyte=0 direction="outgoing" msg="A rating error occurs" error="unknown"

容量規劃試算(Capacity Planning)

變更生效後的第一個小時內,系統共收集到 5,415 筆 WebFilter 紀錄(涵蓋 21 台工作站、315 個外部網站)。

  • 流量放大效應:原先僅紀錄 Traffic Deny 時,每小時僅約 1,100 筆日誌,掛上 WebFilter 全監看後,由於每個網頁請求都會觸發 UTM 事件,整體日誌暴增至每小時約 10,000 ~ 15,000 筆,放大接近 10 倍。
  • 雜訊觀察:單一工作站上的 Firefox 網路連線探測(連線到 generate_204)一小時便觸發了 2,178 次請求,佔整體 40%。維運者在出報表時必須學會辨識這類機器特徵,然後進行降噪工程。

AUP 核心日誌欄位對照表

欄位名稱 範例值 維運與稽核用途
srcip 192.168.2.23 發動連線的工作站 IP(WebFilter 事件不含 srcname,需透過 IP 識別或關聯)
hostname docs.victoriametrics.com 目標網站名稱。HTTPS 取自 SNI,HTTP 取自 Host 標頭
url https://docs.victoriametrics.com/ 存取路徑。在證照檢查模式下,HTTPS 僅保留主機,HTTP 則有完整 URI
catdesc Information Technology FortiGuard 分類。授權過期時整欄為空
eventtype / action ftgd_err / passthrough 處置動作。阻擋時通常為 ftgd_blk / blocked

解析大地雷:LogsQL 中的 hostname 命名衝突

RFC 5424 Syslog 標頭自帶 hostname(代表防火牆主機名 fgt-edge),而 FortiGate 訊息內容裡也包含 hostname(代表目標網站)。
若直接執行 unpack_logfmt,訊息內的網站名稱會覆蓋掉防火牆名稱!
正確寫法:在解析前先執行 rename hostname as fgt。


3. 三條維運必備的 LogsQL 查詢

-- 1. 依工作站列出造訪網站排行(過去 7 天)
_time:7d hostname:=fgt-edge "type=\"utm\"" "subtype=\"webfilter\""
  | rename hostname as fgt
  | unpack_logfmt from _msg fields (srcip, hostname, catdesc, action)
  | stats by (srcip, hostname, catdesc) count() as n
  | sort by (srcip, n desc) 
  | limit 500

-- 2. 網站類別存取分布(放行 vs 阻擋)
_time:7d hostname:=fgt-edge "type=\"utm\"" "subtype=\"webfilter\""
  | rename hostname as fgt
  | unpack_logfmt from _msg fields (catdesc, action)
  | stats by (catdesc, action) count() as n 
  | sort by (n) desc

-- 3. 異常阻擋清單(依工作站與網站分類)
_time:7d hostname:=fgt-edge "subtype=\"webfilter\"" "action=\"blocked\""
  | rename hostname as fgt
  | unpack_logfmt from _msg fields (srcip, hostname, catdesc, action)
  | filter action:=blocked
  | stats by (srcip, hostname, catdesc) count() as n 
  | sort by (n) desc 
  | limit 50

Grafana:依工作站列出造訪網站清單,catdesc 欄位空白即為授權過期的狀態


二、離線下載的防火牆 log 靠純本機檢視器處理

面對向電信商租賃、無法自訂 Syslog 的代管防火牆,我只能取得管理後台匯出的文字檔。為此,我設計了開源專案 fortigate-log-viewer。

它採用 Vite + React 開發,利用瀏覽器端 JavaScript 直接解析百萬行 Log,完全不需要後端資料庫,更嚴格遵守資安隱私邊界。

1. 真正離線的零信任原則

舊版本在讀取日誌時,會主動拿連線日誌裡的裸 IP 去連 Google DoH(DNS over HTTPS)查詢 PTR 反查紀錄。
在 v0.1.0 中完成重構:

  • 預設關閉所有外部 DNS 請求。
  • 新增「反查公開 IP」手動按鈕,並於介面明確提示連線端點(dns.google)。
  • 嚴格過濾 RFC 1918 私有網段、Loopback、Link-Local 等位址,絕對禁止送出內網 IP。

2. 時區陷阱:消失的 8 小時

在解析 FortiOS 日誌時,踩到了經典的瀏覽器時區雷區:
原先程式使用 toISOString().split('T')[0] 預設載入當日資料,這取到的是 UTC 日期,但後續篩選引擎卻以操作者的本地時間(UTC+8)進行比對。
結果導致台灣時間凌晨 00:00 到 08:00 的日誌,在匯入後瞬間被全部過濾掉,畫面永遠顯示「符合條件 0 筆」!經改寫以 Local Time 實體處理時間,並於 CI 流程中強制加入 TZ=Asia/Taipei 自動化測試,徹底封殺此問題。

3. 安全部署容器

為杜絕供應鏈風險,Docker 映像檔捨棄過期的 Node 20,升級至 Node 22,並全面以雜湊 Digest 固定版本:

FROM node:22-alpine@sha256:0a7108bf6c7bf5de370ffb1a3ed6be93d405b43ff159f681a8d18c0e2bc2e402 AS builder
FROM nginx:alpine@sha256:df221db836e1754089190208cee7eeda94f233197056426eda74a43ab1abeac2 AS runner

啟動只需一行,僅綁定本機端點:

docker compose up -d --build # 存取 http://127.0.0.1:5173

fortigate-log-viewer 介面:精確解析行數對帳、用戶存取分類與手動反查防護


三、兩端對齊:不可妥協的資料欄位契約

線上與離線要能產出一致的報告,關鍵在於跨系統欄位定義的正規化契約:

統一目標 解析優先權順序 設計依據與實務考量
工作站識別 user $\to$ srcname $\to$ srcip 有 AD 驗證取帳號,無認證取主機名,皆無則退回 IP 位址。因 WebFilter 日誌不含主機名,本場域最終以 IP 收斂
目標網站 hostname $\to$ dstip 嚴格排除 url 欄位!避免 url="/" 與完整 URI 被切成兩個不同站點
分類狀態 catdesc $\to$ 缺值填 Unrated 當 FortiGuard 授權失效時,統一歸納為未評等,禁止以 Protocol(如 HTTPS)誤填為類別
阻擋判斷 action 符合 block / deny / dropped 等關鍵字 UTM 放行狀態通常標註為 passthrough,其餘視為阻擋
基準時間 線上取 _time,離線取 eventtime $\to$ date+time+tz 均轉為微秒級 Epoch 絕對時間軸

四、同一份檔案兩邊跑:雙向驗證實戰

為驗證統計邏輯一致性,透過自動化比對腳本 aup-compare.sh 處理。它會臨時啟動一個乾淨的 VictoriaLogs 實例,將手動匯出的日誌載入線上端,同時交給離線 Python 引擎分析,最後以 diff 比對產出的 Markdown 資料表。

$ sh firewall/aup-compare.sh fgt-webfilter-2026-10-08.log
fortigate-export-load: 2160 lines, 2160 loaded, 0 skipped (no key=value or no time)
online : ~/day24-aup/raw/compare/online.md
offline: ~/day24-aup/raw/compare/offline.md
aup-compare: SAME (93 table rows)

雙向比對:線上產出與離線報告在工作站連線統計完全相符

偵錯記實:比對過程中發現的四個細微偏差

  1. 設備名稱遺失:FortiGate 記憶體日誌匯出(Memory Log)中完全沒有 devname 欄位。線上載入器預設查無主機名而噴出空值,修正方式為在讀取時預設補上 --devname FortiGate。
  2. 毫秒級時間邊界漂移:Syslog 標頭的 _time 只精準到整秒,而內部 eventtime 為奈秒。兩者量測存在 -1.42s 至 +0.95s 的系統延遲,在查詢時間視窗邊緣容易有 1~3 筆的邊界落差,比對時需在視窗邊界放寬兩秒以求精準。
  3. 時區解析基準:離線檔若缺少時區字尾,解析容易偏離,工具全面強制以 tz="+0800" 解析。
  4. 無時間標記行:匯出檔表頭常包含註解字串,解析器必須於橫幅誠實印出 2160 解析 + 0 略過,做到百分之百精確對帳。

五、隱私與合規治理(ISO 27701 視角)

WebFilter 紀錄了員工的數位足跡,屬於高度敏感的個人資料(PII)。收集不是為了監控,而是為了資安防護與事故歸因。

                         [ 隱私保護邊界 ]
       HTTP 流量  ───────( 完整路徑暴露 )───────>  [ 協定原罪:難以遮蔽 ]
       HTTPS 流量 ───────( 僅截取 SNI FQDN )────>  [ 合規推薦:路徑隱匿 ]
  • 資料最小化(Data Minimization):
    維持使用 certificate-inspection,HTTPS 不解密,僅記錄造訪之主機名,不觸碰個人通訊內容、網址參數及 Payload。
  • 儲存分離與熱層週期:
    日誌預設保留 90 天。由於日誌具敏感性,不宜隨意匯入長期不可竄改的 WORM 封存層,若場域需要長期封存,應將 WebFilter 的 Syslog 目標與標準網路流量拆分為不同 Target。
  • 存取權限審查:
    日誌調閱需落實「最小權限原則」(PoLP),僅限授權資安維運人員經正式審批程序方可連線查詢,查詢日誌本身也需受 Audit Log 監控。

六、自動化告警:從海量日誌提煉資安威脅

一般同仁誤觸無害被擋網站,屬於常態維運,應排程產出週報,不應觸發即時警報(避免警報疲勞)。唯有符合特定異常模式時,才需由 Prometheus 介入告警:

規則名稱 嚴重層級 觸發條件 設計意圖
AupUrgentCategoryHit Critical 踩中惡意網址、釣魚站或垃圾郵件分類 $\ge 1$ 筆 防火牆雖已攔截,但代表工作站可能已被釣魚攻擊或植入後門,需立即隔離調查
AupBlockedBurst Warning 單一主機一小時內遭攔截 $\ge 20$ 次 排除人為誤點,通常代表惡意外掛或殭屍程式在持續嘗試對外連線
AupSilent Info 連續 6 小時全網 WebFilter 紀錄為 0 筆 防呆機制:偵測是否有人誤關 Profile 或 Syslog 連線中斷
AupReportStale Warning 背景稽核排程超過 30 分鐘未正常產出 靜默失效防護,並連動 Alertmanager Inhibit 抑制其他衍生報警

維運技巧:防止 Prometheus 假警報

在實作 AupSilent 規則時,當防火牆無日誌送出,LogsQL stats by 產出的指標序列會直接消失,導致 PromQL 條件判斷無從成立。
我透過排程回報腳本,明確設定環境變數 AUP_EXPECT=fgt-edge,讓腳本在無資料時主動寫入數值 0,讓監控系統能確實捕捉到「死寂」狀態。

Prometheus AUP 監控規則狀態,四條規則均處於正常監控中


七、快速上手指令彙整

1. 部署離線檢視工具

git clone https://github.com/ivanusto/fortigate-log-viewer
cd fortigate-log-viewer
docker compose up -d --build
# 瀏覽本機端點: http://127.0.0.1:5173

2. 線上日誌查詢與比對驗證

# 1. 驗證收集端已收到第一筆資料
curl -s http://127.0.0.1:9428/select/logsql/query \
  -d 'query=_time:1h hostname:=fgt-edge "subtype=\"webfilter\"" | stats count()'

# 2. 測試匯出日誌兩端比對腳本
sh firewall/aup-compare.sh fgt-webfilter-2026-10-08.log

# 3. 執行 Prometheus 規則單元測試
promtool check rules prometheus/rules/aup.yml
promtool test rules tests/rules_aup_test.yml

結語與下集預告

建立 AUP 的監控不是為了製造不信任,而是為了在資安風暴來臨時,用扎實的系統足跡保護企業與同仁。我實作的方式,儘量用最少量的個資揭露(SNI 檢視),換取了關鍵的追溯能力,並透過線上與離線的雙軌工具,確保不論設備由誰託管,都能得到相同標準的解答。

在今天設定 FortiGate 的過程中,過期的 FortiGuard 授權也差點踩中斷網地雷,而離線工具的 Docker 映像檔也提醒了 Node 20 已經默默步入 EOL。

明天,Day 25 將進入「基礎架構資產的 EOL(生命週期終止)監控」,看看如何把韌體更新、作業系統支援到期日全面轉化為自動化告警指標,不再讓過期組件成為架構中的隱形定時炸彈。


相關專案與參考資料


上一篇
Day 23|日誌找不到原因?從 tcpdump 最小權限封包擷取到 WORM 封存的網路排錯實戰
系列文
地端機房的三十天維運:開源服務封裝、GPU 節點守護與可稽核的變更管理 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言